/* ePaper with HTTP
 * 
 *  SPI分配
 *     SPI1_HOST, (对应SPI0)外部flash
 *     SPI2_HOST, (对应SPI1)GDEQ0426T82
 *     SPI3_HOST, (对应SPI2)？？SD卡
 * 
 * 
 *  
 */

#include <stdio.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
//
#include "esp_system.h"
#include "esp_log.h"
//
#include "driver/gpio.h"
#include "driver/spi_master.h"
//
#include "nvs_flash.h"
//
#include "string.h"
//
#include "./main.h"
#include "GDEQ0426T82/EPD_W21.h"
#include "HTTPServer/WebServer.h"
#include "SDCard/SDCard.h"
#include "Button/Button.h"


/************************************************************************
 * DEFINES
 ************************************************************************/
#define TAG_MAIN             "EPD with HTTP"

// LED
#define PIN_LED4        12
#define PIN_LED5        13
// SPI bus
#define SPI_HOST_USING  SPI2_HOST //HSPI_HOST
#define SPI_PIN_MOSI    8
#define SPI_PIN_MISO    5
#define SPI_PIN_SCLK    4


/************************************************************************
 * VARIABLES
 ************************************************************************/
// uint8_t BlackImage[EPD_ARRAY];
char TmpFilePath[FILE_PATH_LEN_MAX];

/************************************************************************
 * FUNCTIONS DEFINE
 ************************************************************************/
void __task_led_blink(void * arg);
void __ESP32_SPI_Bus_Init(spi_host_device_t host_id);
//
// void iot_btn_init();

/************************************************************************
 * APPLICATION MAIN
 ************************************************************************/
void app_main(void)
{
    //------------ init nvs
    esp_err_t ret = nvs_flash_init();
    if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    ESP_LOGI(TAG_MAIN, "nvs init done");

    //------------ statr Blink Task
    xTaskCreate(__task_led_blink, "task_led", 2048, NULL, 12, NULL);
    ESP_LOGI(TAG_MAIN, ">> start task - blink");

    //------------ init SPI bus
    __ESP32_SPI_Bus_Init(SPI_HOST_USING);

    //------------ init SDCard
    ret = SDCard_Init(SPI_HOST_USING);
    if(ret == ESP_OK)
    {
        //将SDCard处理函数交给WebServer
        handler_SDCardTest = SDCard_Test;
        //
        ESP_LOGI(TAG_MAIN, ">> init SDCard");
        // //test
        // // SDCard_Test_2(); //测试用函数
        // char tmp_names[9][50];
        // // uint8_t i;
        // SDCard_File_ListAllNames(MOUNT_POINT"/web_files");
        // // SDCard_File_GetNames(1, tmp_names); //1是Page
        // SDCard_File_GetNames(tmp_names);
        // // for(i = 0; i < 10; i++)
        // // {
        //     ESP_LOGI(TAG_MAIN, "\t%s", tmp_names[0]);
        // // }
    }
    else
    {
        ESP_LOGI(TAG_MAIN, ">> init SDCard failed !!!");
    }

    //------------ init EPD
    // 初始化GPIO & 添加SPI device
    ePaper_InitHardware(SPI_HOST_USING);
    // 将EPD处理函数交给WebServer
    // handler_ePaperSetData = ePaper_SetImgData; //TODO:ePaper_SetImgData不再使用
    handler_ePaperDisplay = ePaper_FullDispaly;
    handler_ePaperResetIdx = ePaper_ResetImgIndex;
    // GUI
    // ePaper_Test_1(); //测试用函数
    // ePapre_Test_2_UiGenerate(); //测试用函数
    //
    ESP_LOGI(TAG_MAIN, ">> init ePaper");

    //------------ start HTTP Task
    ESP_ERROR_CHECK(WebSer_InitSoftAP());
    ESP_LOGI(TAG_MAIN, ">> start task - HTTP Server");

    //------------ init button
    Btn_init();

    //------------------ end
}



/************************************************************************
 * FUNCTIONS IMPLEMENT - inner
 ************************************************************************/
void __task_led_blink(void * arg)
{
    static uint16_t led_state = 0;
    // uint16_t cnt = 0;

    //-------- init LED pin
    gpio_config_t io_config = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_OUTPUT,
        // .pin_bit_mask = (1ULL<<PIN_LED4) | (1ULL<<PIN_LED5),
        .pin_bit_mask = 1ULL<<PIN_LED5,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en = GPIO_PULLUP_DISABLE,
    };
    gpio_config(&io_config);

    //-------- task loop
    for(;;)
    {
        led_state++;
        // gpio_set_level(PIN_LED4, led_state%2);
        gpio_set_level(PIN_LED5, (led_state+1)%2);
        vTaskDelay(20);
    }

    //-------- end
    vTaskDelete(NULL);
}


// @brief: SPI bus init(SPI2_HOST)
//        SPI0/1为SPI Memory模式; SPI2为GP SPI
//
//        SPI bus init需要指定MOSI/MISO/SCLK, 
//        而CS在各个SPI device init时指定
//
//        WP(WriteProtect)/HD(HolD)暂未指定
//
void __ESP32_SPI_Bus_Init(spi_host_device_t host_id)
{
    esp_err_t ret;

    spi_bus_config_t spiBusCfg = {
        .mosi_io_num = SPI_PIN_MOSI,
        .miso_io_num = SPI_PIN_MISO,
        .sclk_io_num = SPI_PIN_SCLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 160*800*2+8  //TODO: 这里太大了???
    };

    ret = spi_bus_initialize(host_id, &spiBusCfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
}



/************************************************************************
 * FUNCTIONS IMPLEMENT - outer
 ************************************************************************/
// const char * default_file_path = "/EPD/bk/bk.txt";

//=========================== Gui图像保存到本地
// description:
//
int8_t Save_GuiImg_to_File(char *file_path)
{
    // GUIImg写入File
    // 一个GUIImg[i]拆成高4bit和低4bit, 放入两个tmp[]中
    char tmp[FILE_WRITE_BLOCK_SIZE];
    uint16_t i, j;
    uint8_t gui_val;

    //检查ImgIndex, 确认Photo正常接收
    if(ePaper_CheckImgIndex() == -1)
    {
        ESP_LOGI(TAG_MAIN, "Save_GuiImg_to_File: error ImgIndex");

        return -1;
    }

    //获取file path
    if(file_path == NULL)
    {
        file_path = TmpFilePath;
        memset(file_path, '\0', FILE_PATH_LEN_MAX);
        sprintf(file_path, "%s", DEFAULT_BK_FILE_PATH); //无需设置MOUNT_POINT, 以下会补全

        ESP_LOGI(TAG_MAIN, "Save_GuiImg_To_File: using default file path");
    }
    //在SDCard中创建文件
    if(SDCard_File_Open(file_path, FILE_MODE_WRITE) == ESP_FAIL) //SDCard_File_Open()会补全路径
    {
        ESP_LOGI(TAG_MAIN, "create file in SDCard failed !!!");
        return -1;
    }
        
    //将GUIImg数据拆解成字符
    tmp[1000] = '\0';
    for(i = 0; i < EPD_ARRAY;)
    {
        for(j = 0; j < 1000; ++j, ++i) //j<1000, 将消耗500个i   一行控制在1000以内
        {
            gui_val = ePaper_GuiImg_GetVal(i); //取出GUIImg[i]
            tmp[j] = (gui_val & 0xF) + 'a'; //转字符
            tmp[++j] = ((gui_val >> 4) & 0xF) + 'a';
        }
        SDCard_File_Write_Img(tmp, 1000); //将执行96次, EPD_ARRAY/500=480*800/8/500=96
        //
        vTaskDelay(1); //for WDT
    }
    SDCard_File_Close();

    return 0;
}

//=========================== 从本地加载Gui图像
// description:
//      从SDCard读取图像文件初始化GUIImg(仅初始化, 不显示)
//
int8_t Load_GuiImg_from_File(char *file_path)
{
    if(file_path == NULL)
    {
        // file_path = DEFAULT_BK_FILE_PATH;
        
        file_path = TmpFilePath;
        memset(file_path, '\0', FILE_PATH_LEN_MAX);
        sprintf(file_path, "%s", DEFAULT_BK_FILE_PATH);

        ESP_LOGI(TAG_MAIN, "Load_GuiImg_from_File: using default file path");
    }

    if(SDCard_File_Open(file_path, FILE_MODE_READ) == ESP_OK)
    {
        // uint 16_t img_val;
        char img_val[FILE_WRITE_BLOCK_SIZE];
        // uint16_t tmp = 0;

        ePaper_GuiImg_Init(); //用快刷初始化GUI

        ePaper_ResetImgIndex(); //重置PhotoImg的序号
        // ESP_LOGI(TAG_MAIN, "Load_GuiImg_from_File: start read tmp.txt"); 
        while (SDCard_File_Read_Img(img_val, FILE_WRITE_BLOCK_SIZE) == ESP_OK) //应该固定读取到96行, 每行1000个字符
        {
            //设置EPD
            ePaper_SetImgDataByChar(img_val, strlen(img_val) - 1, Img_Type_Gui); //填充GUIImg   -1为'\n'
            // ESP_LOGI(TAG_BTN, "siezof=%d", sizeof(img_val));
            //重置缓存数组
            memset(img_val, '\0', sizeof(img_val)); 

            vTaskDelay(1); //for WDT
        }

        SDCard_File_Close();
        ESP_LOGI(TAG_MAIN, "Load_GuiImg_from_File: end of set tmp.txt");  

        for(uint8_t i = 0; i < FILE_NUM_IN_PAGE; i++)
            ePaper_GuiImg_UpdateSelect(i, true);
        // ePaper_GuiImg_Init(); //用快刷初始化GUI
        ePaper_GuiImg_Display();
    }
    else
    {
        return -1;
    }

    return 0;
}

//=========================== 用文件列表刷新Gui, 并显示
// description:
//
void Update_GuiImg_from_List()
{
    char tmp_names[FILE_NUM_IN_PAGE][FILE_NAME_LEN_MAX];
    int8_t file_num;
    // uint8_t i;

    //获取文件列表
    file_num = SDCard_File_GetNames(tmp_names); //用CurrentPage获取文件名, CurrentPage在内部指定
    // for(i = 0; i < FILE_NUM_IN_PAGE; i++)
    // {
    //     ESP_LOGI(TAG_MAIN, "\t%s", tmp_names[i]);
    // }
    //刷新GuiImg
    ePaper_GuiImg_UpdateList(file_num, tmp_names, false);

    //显示GUIImg
    ePaper_GuiImg_Display();

    ESP_LOGI(TAG_MAIN, "Update_GuiImg_from_List: end");
}

//=========================== 为Gui设置选择点, 并显示
// description:
//      先获取CurrentIdx, 清除当前选择点, 
//      再按照step移动(+1/-1)设置CurrentIdx, 画出当前选择点
//
int8_t Update_GuiImg_to_Select(int8_t step)
{
    uint8_t select_idx;
    int8_t is_page_change;

    //清除上次选择
    select_idx = SDCard_File_GetSelectPosition();
    ESP_LOGI(TAG_MAIN, "Update_GuiImg_to_Select: last idx=%d", select_idx);
    ePaper_GuiImg_UpdateSelect(select_idx, true);
    // ePaper_GuiImg_UpdateSelect_Del(select_idx);
    //设置本次选择
    is_page_change = SDCard_File_CurrentIdx_Set(step);
    select_idx = SDCard_File_GetSelectPosition();
    ESP_LOGI(TAG_MAIN, "Update_GuiImg_to_Select: current idx=%d", select_idx);
    ePaper_GuiImg_UpdateSelect(select_idx, false);
    // ePaper_GuiImg_UpdateSelect_Add(select_idx);

    //显示GUIImg
    ePaper_GuiImg_Display();

    // // uint8_t select_idx = SDCard_File_CurrentIdx_Get();
    // uint8_t select_idx = SDCard_File_GetSelectPosition();
    // //
    // //GuiImg设置选择点
    // ePaper_GuiImg_UpdateSelect(select_idx);
    // //显示GUIImg
    // // vTaskDelay(3000 / portTICK_PERIOD_MS);
    // ePaper_GuiImg_Display();

    ESP_LOGI(TAG_MAIN, "Update_GuiImg_to_Select: is_page_change %d", is_page_change);

    return is_page_change;
}

//=========================== 保存Photo到文件(实际是将/EPD/photo.txt拷贝到/EPD/img/中)
// description:
//
int8_t Save_PhotoImg_to_File()
{

    //打开src文件
    if(SDCard_File_Open(DEFAULT_PHOTO_FILE_PATH, FILE_MODE_READ) == ESP_FAIL) //SDCard_File_Open()会补全路径
    {
        ESP_LOGI(TAG_MAIN, "Save_PhotoImg_to_File: open photo.txt failed!!!");
        return -1;
    }

    //src复制到指定位置
    if(SDCard_File_Copy_Img() == -1)
        ESP_LOGI(TAG_MAIN, "Save_PhotoImg_to_File: copy failed!!!");
    else
        ESP_LOGI(TAG_MAIN, "Save_PhotoImg_to_File: copy ok");

    //关闭src文件
    SDCard_File_Close();

    return 0;



    // // GUIImg写入File
    // // 一个GUIImg[i]拆成高4bit和低4bit, 放入两个tmp[]中
    // char tmp[FILE_WRITE_BLOCK_SIZE];
    // uint16_t i, j;
    // uint8_t gui_val;

    // //检查ImgIndex, 确认Photo正常接收
    // if(ePaper_CheckImgIndex() == -1)
    // {
    //     ESP_LOGI(TAG_MAIN, "Save_GuiImg_to_File: error ImgIndex");

    //     return -1;
    // }

    // //获取file path
    // if(file_path == NULL)
    // {
    //     // file_path = DEFAULT_BK_FILE_PATH;
    //     // ESP_LOGI(TAG_MAIN, "Save_GuiImg_To_File: using default file path");

    //     uint32_t random = esp_random();

    //     file_path = TmpFilePath;
    //     memset(file_path, '\0', FILE_PATH_LEN_MAX);
    //     sprintf(file_path, "%s%5ld.txt", DEFAULT_IMG_DIR_PATH, random % 0xFFFF0000); //无需设置MOUNT_POINT, 以下会补全

    //     ESP_LOGI(TAG_MAIN, "Save_GuiImg_To_File: generate file name %s", file_path);
    // }
    // //在SDCard中创建文件
    // if(SDCard_File_Open(file_path, FILE_MODE_WRITE) == ESP_FAIL) //SDCard_File_Open()会补全路径
    // {
    //     ESP_LOGI(TAG_MAIN, "create file in SDCard failed !!!");
    //     return -1;
    // }
        
    // //将GUIImg数据拆解成字符
    // tmp[1000] = '\0';
    // for(i = 0; i < EPD_ARRAY;)
    // {
    //     for(j = 0; j < 1000; ++j, ++i) //j<1000, 将消耗500个i   一行控制在1000以内
    //     {
    //         gui_val = ePaper_GuiImg_GetVal(i); //取出GUIImg[i]
    //         tmp[j] = (gui_val & 0xF) + 'a'; //转字符
    //         tmp[++j] = ((gui_val >> 4) & 0xF) + 'a';
    //     }
    //     SDCard_File_Write_Img(tmp, 1000); //将执行96次, EPD_ARRAY/500=480*800/8/500=96
    //     //
    //     vTaskDelay(1); //for WDT
    // }
    // SDCard_File_Close();

    // return 0;
}

//=========================== 读取指定序号文件并显示
// description:
//
int8_t Load_PhotoImg_from_File(void)
{
    char file_name[FILE_PATH_LEN_MAX];

    //获取文件名
    SDCard_File_GetOnePath(file_name); //会使用CurrentPage和CurrentIdx计算文件序号
    //读取对应图像
    if(SDCard_File_Open(file_name, FILE_MODE_READ) == ESP_OK)
    {
        // uint 16_t img_val;
        char img_val[FILE_WRITE_BLOCK_SIZE];
        // uint16_t tmp = 0;

        ePaper_ResetImgIndex();

        ESP_LOGI(TAG_MAIN, "Load_PhotoImg_from_File: start of read data"); 
        while (SDCard_File_Read_Img(img_val, FILE_WRITE_BLOCK_SIZE) == ESP_OK) //应该固定读取到96行, 每行1000个字符
        {
            //设置EPD
            ePaper_SetImgDataByChar(img_val, strlen(img_val) - 1, Img_Type_Photo); //-1为'\n'
            //重置缓存数组
            memset(img_val, '\0', sizeof(img_val)); 

            vTaskDelay(1); //for WDT
        }

        SDCard_File_Close();
        ePaper_FullDispaly();

        ESP_LOGI(TAG_MAIN, "Load_PhotoImg_from_File: end of read data");   
    }
    else
    {
        return -1;
    }

    return 0;
}

//=========================== 删除SDCard中的Photo
// description:
//      删除SDCard中的Photo, 刷新List
//
int8_t Delete_PhotoImg_from_SDCard()
{
    if(SDCard_File_Delete_Img() == 0)
    {
            ESP_LOGI(TAG_MAIN, "delete Photo ok");

            //刷新file list
            SDCard_File_ListAllNames(DEFAULT_IMG_DIR);
            //更新CurrentIdx
            if(SDCard_File_IsCurrentIdxAtTail() == 1)
                Update_GuiImg_to_Select(-1); //如果CurrentIdx在结尾, 要向前移动一
            //清除之前Gui中的list
            ePaper_GuiImg_UpdateList(9, NULL, true);
            //刷新Gui
            Update_GuiImg_from_List();

            return 0;
    }
    else
        return -1;
}
